﻿using System;
using System.Collections.Generic;
using System.Text;

namespace LK.Math
{
    public partial class Bits
    {
		/// <summary>
		/// 将数组arrSource中按位指定的部分内容拷贝至arrDest中按位指定的位置上
		/// </summary>
		/// <param name="arrSource">源ulong数组</param>
		/// <param name="sourceStartBitPositon">源数组上按位计算的起始位置</param>
		/// <param name="bitsCount">需要复制的位数</param>
		/// <param name="arrDest">目标ulong数组</param>
		/// <param name="destIndex">按位计算的覆盖起始位置</param>
		public static void Copy(ulong[] arrSource, int sourceStartBitPositon, int bitsCount, ulong[] arrDest, int destStartBitPositon)
		{
			if (bitsCount == 0) return;
			//最初的代码是C格式的指针，这里改为数组结合startIndex和destIndex来表示
			int startIndex = 0;
			int destIndex = 0;
			int idxEnd;
			if (sourceStartBitPositon < 0) { startIndex += (sourceStartBitPositon - 63) / 64; sourceStartBitPositon &= 63; }
			else if (sourceStartBitPositon >= 64) { startIndex += sourceStartBitPositon / 64; sourceStartBitPositon &= 63; }
			if (destStartBitPositon < 0) { destIndex += (destStartBitPositon - 63) / 64; destStartBitPositon &= 63; }
			else if (destStartBitPositon >= 64) { destIndex += destStartBitPositon / 64; destStartBitPositon &= 63; }

			if (sourceStartBitPositon == 0)
			{
				if (destStartBitPositon == 0)
				{
					idxEnd = (bitsCount >> 6) + destIndex;
					while (destIndex != idxEnd) arrDest[destIndex++] = arrSource[startIndex++];
					if ((bitsCount &= 63) != 0) arrDest[destIndex] = (arrSource[startIndex] & ((~0ul) >> (64 - bitsCount))) | (arrDest[destIndex] & ((~0ul) << bitsCount));
					return;
				}
				idxEnd = ((bitsCount + destStartBitPositon) >> 6) + destIndex;
				if (idxEnd == destIndex)
				{
					arrDest[destIndex] = (arrDest[destIndex] & (((((~0ul)) << (bitsCount + destStartBitPositon)) | (((~0ul)) >> (64 - destStartBitPositon)))))
						| ((arrSource[startIndex] & (((~0ul)) >> (64 - bitsCount))) << destStartBitPositon);
					return;
				}
				arrDest[destIndex] = (arrSource[startIndex] << destStartBitPositon) | (arrDest[destIndex] & (((~0ul)) >> (64 - destStartBitPositon)));
				while (++destIndex != idxEnd) { arrDest[destIndex] = (arrSource[startIndex] >> (64 - destStartBitPositon)) | (arrSource[startIndex + 1] << destStartBitPositon); ++startIndex; }
				if ((bitsCount = (destStartBitPositon + bitsCount) & 63) != 0)
				{
					ulong tmp = (arrSource[startIndex] >> (64 - destStartBitPositon));
					if (bitsCount > (long)destStartBitPositon) tmp |= arrSource[startIndex + 1] << destStartBitPositon;
					arrDest[destIndex] = (arrDest[destIndex] & (((~0ul)) << bitsCount)) | (tmp & (((~0ul)) >> (64 - bitsCount)));
				}
				return;
			}
			if (destStartBitPositon == 0)
			{
				idxEnd = (bitsCount >> 6) + destIndex;
				while (idxEnd != destIndex)
				{
					arrDest[destIndex++] = (arrSource[startIndex] >> sourceStartBitPositon) | (arrSource[startIndex + 1] << (64 - sourceStartBitPositon));
					++startIndex;
				}
				if ((bitsCount &= 63) != 0)
				{
					ulong tmp = arrSource[startIndex] >> sourceStartBitPositon;
					if (bitsCount + sourceStartBitPositon > 64) tmp |= (arrSource[startIndex + 1] << (64 - sourceStartBitPositon));
					arrDest[destIndex] = (arrDest[destIndex] & (((~0ul)) << bitsCount)) | (tmp & (((~0ul)) >> (64 - bitsCount)));
				}
				return;
			}
			idxEnd = ((bitsCount + destStartBitPositon) >> 6) + destIndex;
			if (idxEnd == destIndex)
			{
				ulong tmp = arrSource[startIndex] >> sourceStartBitPositon;
				if (bitsCount + sourceStartBitPositon > 64) tmp |= (arrSource[startIndex + 1] << (64 - sourceStartBitPositon));
				arrDest[destIndex] = (arrDest[destIndex] & (((((~0ul)) << (bitsCount + destStartBitPositon)) | (((~0ul)) >> (64 - destStartBitPositon)))))
					| ((tmp & (((~0ul)) >> (64 - bitsCount))) << destStartBitPositon);
				return;
			}
			arrDest[destIndex] = (((arrSource[startIndex] >> sourceStartBitPositon) | (arrSource[startIndex + 1] << (64 - sourceStartBitPositon))) << destStartBitPositon) | (arrDest[destIndex] & (((~0ul)) >> (64 - destStartBitPositon)));
			if (sourceStartBitPositon == destStartBitPositon)
			{
				while (++destIndex != idxEnd) { arrDest[destIndex] = arrSource[++startIndex]; }
				if ((bitsCount = (destStartBitPositon + bitsCount) & 63) != 0)
				{
					arrDest[destIndex] = (arrDest[destIndex] & (((~0ul)) << bitsCount)) | ((arrSource[startIndex + 1]) & (((~0ul)) >> (64 - bitsCount)));
				}
				return;
			}
			sourceStartBitPositon -= destStartBitPositon;
			if (sourceStartBitPositon < 0)
			{
				sourceStartBitPositon = -sourceStartBitPositon;
				while (++destIndex != idxEnd)
				{
					arrDest[destIndex] = (arrSource[startIndex] >> (64 - sourceStartBitPositon)) | (arrSource[startIndex + 1] << sourceStartBitPositon);
					++startIndex;
				}
				if ((bitsCount = (destStartBitPositon + bitsCount) & 63) != 0)
				{
					ulong tmp = arrSource[startIndex] >> (64 - sourceStartBitPositon);
					if (bitsCount > sourceStartBitPositon) tmp |= arrSource[startIndex + 1] << sourceStartBitPositon;
					arrDest[destIndex] = (arrDest[destIndex] & (((~0ul)) << bitsCount)) | (tmp & (((~0ul)) >> (64 - bitsCount)));
				}
				return;
			}
			while (++destIndex != idxEnd)
			{
				++startIndex;
				arrDest[destIndex] = (arrSource[startIndex] >> sourceStartBitPositon) | (arrSource[startIndex + 1] << (64 - sourceStartBitPositon));
			}
			if ((bitsCount = (destStartBitPositon + bitsCount) & 63) != 0)
			{
				ulong tmp = arrSource[startIndex + 1] >> sourceStartBitPositon;
				if (bitsCount + sourceStartBitPositon > 64) tmp |= arrSource[startIndex + 2] << (64 - sourceStartBitPositon);
				arrDest[destIndex] = (arrDest[destIndex] & (((~0ul)) << bitsCount)) | (tmp & (((~0ul)) >> (64 - bitsCount)));
			}
		}
	}
}
